#include "../logger/log.h"
/* 扩展一个以时间作为日志文件滚动切换类型的日志落地模块
    1.以时间进行滚动，其实是以时间段进行滚动
    2.实现思想：以当前系统时间，取模时间段大小，可以得到当前时间段是第几个时间段
        每次以当前系统时间取模，判断当前文件的时间段是否一致，不一致代表不是同一个时间段
    3.时间段划分：1s、1分钟(60s)、1小时(3600s)、1天(3600*24s)，且时间段都会转换为s为单位计算

*/
enum class TimeGap {
    GAP_SECOND,
    GAP_MINUTE,
    GAP_HOUR,
    GAP_DAY
};
class RollByTimeLogSink : public log::LogSink {
public:
    RollByTimeLogSink(const std::string &base_name, TimeGap gap_type) 
        :base_name_(base_name) {
        // 确定时间段
        switch(gap_type) {
            case TimeGap::GAP_SECOND : gap_size_ = 1; break;
            case TimeGap::GAP_MINUTE : gap_size_ = 60; break;
            case TimeGap::GAP_HOUR : gap_size_ = 3600; break;
            case TimeGap::GAP_DAY : gap_size_ = 3600 * 24; break;
            default : assert(false);
        }
        // 创建目录，防止目录不存在
        log::util::File::create_directory(log::util::File::get_path(base_name));
        // 创建文件，根据基础文件名进行创建
        std::string file_name = create_new_file();
        // 打开文件
        ofs_.open(file_name, std::ios::binary | std::ios::app);
        assert(ofs_.is_open());
        // 初始化当前文件的时间段，以1s为时间段时需要特殊处理，不然cur_gap_就一直是0了
        cur_gap_ = gap_size_ == 1 ? log::util::Date::get_time() : log::util::Date::get_time() % gap_size_;

    }
    virtual void log(const char *data, size_t length) override {
        // 获取系统时间，计算时间段，并与当前日志文件时间段比较
        size_t cur = gap_size_ == 1 ? log::util::Date::get_time() : log::util::Date::get_time() % gap_size_;

        if (cur != cur_gap_) {
            ofs_.close();
            std::string file_name = create_new_file();
            ofs_.open(file_name, std::ios::binary | std::ios::app);
            assert(ofs_.is_open());
            cur_gap_ = cur;
        }
        ofs_.write(data, length);
        assert(ofs_.good());
    }
private:
    std::string create_new_file() {
            // 获取系统当前时间戳
            time_t t = log::util::Date::get_time();
            // 转换为时间结构体
            struct tm tt;
            localtime_r(&t, &tt);
            // 拼接为完整文件名
            std::stringstream file_name;
            file_name << base_name_;
            file_name << tt.tm_year + 1900;
            file_name << tt.tm_mon + 1;
            file_name << tt.tm_mday;
            file_name << tt.tm_hour;
            file_name << tt.tm_min;
            file_name << tt.tm_sec;
            file_name << ".log";
            //返回
            return file_name.str();
        }
private:
    std::string base_name_;//基础文件名
    std::ofstream ofs_;//输出文件流
    size_t gap_size_;//时间段大小
    size_t cur_gap_;// 当前文件所处的时间段
};

int main() {
    // <全局异步日志器测试>
    // 以时间为基准进行日志消息的滚动落地
    std::unique_ptr<log::LoggerBuilder> builder(new log::GlobalLoggerBuilder);
    builder->build_logger_name("async-logger");
    builder->build_Formatter("[%c][%f:%l][%d{%H:%M:%S}]%m%n");
    builder->build_logger_type(log::LoggerType::ASYNC_LOGGER);
    builder->build_sink<RollByTimeLogSink>("./logfile/roll-async-by-time-", TimeGap::GAP_SECOND);
    log::Logger::ptr logger = builder->build();
    
    time_t cur = log::util::Date::get_time();
    size_t cnt = 0;
    while (log::util::Date::get_time() < cur + 5) {
        DEBUG_LOG(logger, "%s[%d]", "测试日志", cnt++);
        usleep(1000);
    }
    // <全局异步日志器测试>
    return 0;
}
